/*
 * pci.cpp
 *
 *  Created on: 2021年3月19日
 *      Author: root
 */
#include <hardwarecommunication/pci.h>
#include <common/types.h>
#include <memorymanagement.h>

using namespace myos::hardwarecommunication;
using namespace myos::common;
using namespace myos::drivers;

void printf(char* str);

void printfHex(uint8_t key);


PeripheralComponentInterconnectDeviceDescriptor::PeripheralComponentInterconnectDeviceDescriptor(){

}
PeripheralComponentInterconnectDeviceDescriptor::~PeripheralComponentInterconnectDeviceDescriptor(){

}

PeripheralComponentInterconnectController::PeripheralComponentInterconnectController()
:dataPort(0xCFC),
 commandPort(0xCF8)
{


}
PeripheralComponentInterconnectController::~PeripheralComponentInterconnectController(){

}

uint32_t PeripheralComponentInterconnectController::Read(uint16_t bus,uint16_t device,int16_t function,int32_t registeroffset){

	uint32_t id=0x1<<31
			|((bus&0xFF)<<16)
			|((device&0x1F)<<11)
			|((function&0x07)<<8)
			|(registeroffset & 0xFC);
	commandPort.Write(id);
	uint32_t result=dataPort.Read();

	return result>>(8*(registeroffset % 4));
}

void PeripheralComponentInterconnectController::Write(uint16_t bus,uint16_t device,uint16_t function,uint32_t registeroffset,uint32_t value){

	uint32_t id=0x1<<31
			|((bus&0xFF)<<16)
			|((device&0x1F)<<11)
			|((function&0x07)<<8)
			|(registeroffset & 0xFC);
	commandPort.Write(id);
	dataPort.Write(value);

}

bool PeripheralComponentInterconnectController::DeviceHasFunctions(uint16_t bus,uint16_t device){

	//用于判断device的功能是否具有此功能，可以加快枚举速度
	//1<<7 =128
	return Read(bus,device,0,0x0E) & (1<<7);
}

void PeripheralComponentInterconnectController::SelectDrivers(DriverManager*  driverManager,InterruptManager* interrupt){
	for(int bus=0;bus<8;bus++){
		for(int device=0;device<32;device++){
			int numFunctions=DeviceHasFunctions(bus,device)? 8: 1;
			for(int function=0;function<numFunctions;function++){

				PeripheralComponentInterconnectDeviceDescriptor dev=GetDeviceDescriptor(bus,device,function);

				if(dev.vendor_id == 0x0000 || dev.vendor_id == 0xFFFF)
					continue;

				for(int barNum=0;barNum<6;barNum++){
					BaseAddressRegister bar=GetBaseAddressRegister(bus,device,function,barNum);
					//只有一个输入和输出
					if(bar.address && (bar.type==InputOutput)){
						dev.portBase=(uint32_t)bar.address;
					}
					myos::drivers::Driver* driver=PeripheralComponentInterconnectController::GetDriver(dev, interrupt);
					if(driver!=0){
						driverManager->AddDriver(driver);
					}
				}

				printf("PCI BUS ");
				printfHex(bus & 0xFF);

				printf(" , DEVICE ");
				printfHex(device & 0xFF);

				printf(" , FUNCTION ");
				printfHex(function & 0xFF);

				printf("= VENDOR ");
				printfHex((dev.vendor_id & 0xFF00) >> 8);
				printfHex(dev.vendor_id & 0xFF);

				printf(", DEVICE ");
				printfHex((dev.device_id & 0xFF00) >> 8);
				printfHex(dev.device_id & 0xFF);

				printf("\n");


			}
		}
	}

}

BaseAddressRegister PeripheralComponentInterconnectController::GetBaseAddressRegister(uint16_t bus,uint16_t device,uint16_t function,uint16_t bar){

	BaseAddressRegister result;
	//获取前七位
	uint32_t headertype=Read(bus,device,function,0x0E)& 0x7F;
	//用于判断存储器大小
	int maxBARs=6-(4*headertype);
	if(bar >= maxBARs){
		return result;
	}

	uint32_t bar_value=Read(bus,device,function,0x10+4*bar);
	result.type=(bar_value & 0x1) ? InputOutput :MemoryMapping ;
	uint32_t temp;

	if(result.type==MemoryMapping){

		//取第二和第三位，用于设置内存映射的大小
		switch((bar_value >>1)&0x3){
			case 0:// 32 bit memory base address registers
			case 1:// 20 bit memory base address registers
			case 2:// 64 bit memory base address registers
				break;
		}
	}
	else{
		//IntputOutput
		result.address=(uint8_t *) (bar_value & ~0x3);   //取最后两位
		result.prefetchable=false;

	}

	return result;
}


Driver* PeripheralComponentInterconnectController::GetDriver(PeripheralComponentInterconnectDeviceDescriptor dev,InterruptManager* interrupt){

	Driver* driver=0;
	switch(dev.vendor_id){
		case 0x1022://AMD
			switch(dev.device_id){
				case 0x2000://am79c973
					driver=(amd_am79c973* )MemoryManager::activeMemoryManager->malloc(sizeof(amd_am79c973));
					if(driver!=0){
						new (driver)amd_am79c973(...);
					}
					printf("AMD am79c973");
					break;
			}
			break;
		case 0x8086://Intel
			break;

	}

	switch(dev.class_id){
		case 0x03:  //graphics
			switch(dev.subclass_id){
				case 0x00:
					printf("VGA ");
				break;
			}
			break;
	}
 return driver;
}

PeripheralComponentInterconnectDeviceDescriptor PeripheralComponentInterconnectController::GetDeviceDescriptor(uint16_t bus,uint16_t device,uint16_t function){

	PeripheralComponentInterconnectDeviceDescriptor result;

	result.bus=bus;
	result.device=device;
	result.function=function;

	result.vendor_id=Read(bus,device,function,0x00);
	result.device_id=Read(bus,device,function,0x02);

	result.class_id=Read(bus,device,function,0x0b);
	result.subclass_id=Read(bus,device,function,0x0a);
	result.interface_id=Read(bus,device,function,0x09);

	result.revision=Read(bus,device,function,0x08);
	result.interrupt=Read(bus,device,function,0x3c);


	return result;


}

